/****h* scdbxml/tree.c
 *  NAME
 *    tree.c
 *  DESCRIPTION
 *********/
#include "tree.h"

/****f* tree.c/getDocument
 *  NAME
 *    getDocument
 *  SYNOPSIS
 *    void getDocument(userReaderCtxt ctxt, int doc_id) 
 *  ARGUMENTS
 *  RETURN TYPE
 *  AUTHOR
 *  SOURCE
*/
void getDocument(userReaderCtxt ctxt, int doc_id) 
	/*{{{*/
{
	 while (1) 
		 {
				/*
				 * bind doc_id to sql statement
				 */
				if (SQLITE_OK != sqlite3_bind_int(ctxt->getDocument, 1, doc_id) ||
						SQLITE_OK != sqlite3_bind_int(ctxt->getDocument, 2, doc_id) ||
						SQLITE_OK != sqlite3_bind_int(ctxt->getDocument, 3, doc_id) ||
						SQLITE_OK != sqlite3_bind_int(ctxt->getDocument, 4, doc_id) ||
						SQLITE_OK != sqlite3_bind_int(ctxt->getDocument, 5, doc_id)) 
					{
						 userReaderCtxtError(ctxt, SCDBXML_BIND, __LINE__, __FILE__);
						 break;
					}
	 
				/*
				 * get rows from query into nodes array
				 */
				while (SQLITE_ROW == sqlite3_step(ctxt->getDocument)) 
					{
						 struct _node n;
						 
						 /*
							* check that nodes buffer won't get full
							* and double it when needed
							*/
						 while (ctxt->max_nodes <= ctxt->node_count) 
							 {
									ctxt->max_nodes *= 2;
									ctxt->nodes = (node) realloc(ctxt->nodes, 
																							 sizeof(struct _node) * ctxt->max_nodes
																							 );
									if (NULL == ctxt->nodes) 
										{
											 userReaderCtxtError(ctxt, SCDBXML_MALLOC, __LINE__, __FILE__);
											 break;
										}
							 }
						 if (SCDBXML_OK != ctxt->error) 
							 {
									break;
							 }
						 
						 /*
							* get current node into convenience variable
							*/
						 n = ctxt->nodes[ctxt->node_count];
						 n.x = sqlite3_column_int(ctxt->getDocument, 1); /* x */
						 n.y = sqlite3_column_int(ctxt->getDocument, 2); /* y */
						 n.depth = sqlite3_column_int(ctxt->getDocument, 4); /* depth */
						 n.type = sqlite3_column_int(ctxt->getDocument, 5); /* type */
						 n.uri_len = sqlite3_column_bytes(ctxt->getDocument, 8); /* uri len */
						 n.prefix_len = sqlite3_column_bytes(ctxt->getDocument, 9); /* prefix len */
						 n.name_len = sqlite3_column_bytes(ctxt->getDocument, 6); /* name len */
						 n.value_len = sqlite3_column_bytes(ctxt->getDocument, 7); /* value len */
						 
						 n.nod_id = sqlite3_column_int(ctxt->getDocument, 0);
						 n.doc_id = sqlite3_column_int(ctxt->getDocument, 3);
						 
						 /*
							* name
							*/
						 n.name = n.name_len ? xmlCharStrndup((char *) 
																									sqlite3_column_text(ctxt->getDocument, 
																																			6), 
																									n.name_len) : NULL;
						 
						 /*
							* value
							*/
						 n.value = n.value_len ? xmlCharStrndup((char *) 
																										sqlite3_column_text(ctxt->getDocument, 
																																				7), 
																										n.value_len) : NULL;
						 
						 /*
							* namespace uri
							*/
						 n.uri = n.uri_len ? xmlCharStrndup((char *) 
																								sqlite3_column_text(ctxt->getDocument, 
																																		8), 
																								n.uri_len) : NULL;
						 
						 /*
							* possible namespace prefix
							*/
						 n.prefix = n.prefix_len ? xmlCharStrndup((char *) 
																											sqlite3_column_text(ctxt->getDocument, 
																																					9), 
																											n.prefix_len) : NULL;
						 
						 /*
							* put node back and increment node count
							*/
						 ctxt->nodes[ctxt->node_count] = n;
						 ++ ctxt->node_count;
					}

				/*
				 * see if there was error in above while loop
				 */
				if (SCDBXML_OK != ctxt->error) 
					{
						 break;
					}
				
				/*
				 * finished with sql statement
				 */
				if (SQLITE_OK != sqlite3_finalize(ctxt->getDocument)) 
					{
						 userReaderCtxtError(ctxt, SCDBXML_FINALIZE, __LINE__, __FILE__);
						 break;
					}
				
				/*
				 * have nodes so put them into document
				 */
				buildDocument(ctxt);
				
				break;
		 }
}
/*}}}*/

void
/************ getDocument */
/****f* tree.c/buildDocument
 *  NAME
 *    buildDocument
 *  SYNOPSIS
 *    buildDocument(userReaderCtxt ctxt)
 *  ARGUMENTS
 *  RETURN TYPE
 *  AUTHOR
 *  SOURCE
*/
	buildDocument(userReaderCtxt ctxt)
	/*{{{*/ 
{
	 int i, j, old_x, old_y, old_depth, r;
	 xmlTextWriterPtr writer;
	
	 while (1) 
		 {
				/*
				 * create document and writer
				 */
				writer = xmlNewTextWriterDoc(&ctxt->doc, 0);
				if (NULL == writer) 
					{
						 userReaderCtxtError(ctxt, SCDBXML_XML, __LINE__, __FILE__);
						 break;
					}
	 
				if (-1 == xmlTextWriterStartDocument(writer,
																						 "1.0",
																						 "UTF-8",
																						 NULL)) 
					{
						 userReaderCtxtError(ctxt, SCDBXML_XML, __LINE__, __FILE__);
						 break;
					}
	 
				/*
				 * initialise old x and y
				 */
				old_x = 0;
				old_y = RAND_MAX;
				old_depth = 0;

				/*
				 * loop over nodes
				 */
				for (i = 0; i < ctxt->node_count; ++ i) 
					{
						 struct _node n = ctxt->nodes[i];
						 /*
							* close open nodes if needed
							*/
						 if (n.type == XML_ELEMENT_NODE && 
								 n.x > old_y)
							 {
									for (j = n.depth; j <= old_depth; ++ j) 
										{
											 if (-1 == xmlTextWriterEndElement(writer)) 
												 {
														userReaderCtxtError(ctxt, SCDBXML_XML, __LINE__, __FILE__);
														break;
												 }
										}
									if (SCDBXML_OK != ctxt->error) 
										{
											 break;
										}
							 }
						 
						 /*
							* now proceed with current node
							*/
						 switch (n.type) 
							 {
								case XML_ATTRIBUTE_NODE:
									r = -1;
									/*
									 * attribute value has to be empty string if NULL
									 */
									if (0 == n.value_len) 
										{
											 n.value = (xmlChar*) "";
										}
									
									if (n.uri_len) 
										{
											 r = xmlTextWriterWriteAttributeNS(writer,
																												 n.prefix,
																												 n.name,
																												 n.uri,
																												 n.value);
										}
									else 
										{
											 r = xmlTextWriterWriteAttribute(writer,
																											 n.name,
																											 n.value);
										}
									if (-1 == r) 
										{
											 userReaderCtxtError(ctxt, SCDBXML_XML, __LINE__, __FILE__);
											 break;
										}
									DBG(fprintf(stderr, "attribute %s\n", n.name));
									break;
								case XML_ELEMENT_NODE:
									r = -1;
									if (n.uri_len) 
										{
											 r = xmlTextWriterStartElementNS(writer,
																											 n.prefix,
																											 n.name,
																											 n.uri);
										}
									else 
										{
											 r = xmlTextWriterStartElement(writer,
																										 n.name);
										}
									if (-1 == r) 
										{
											 userReaderCtxtError(ctxt, SCDBXML_XML, __LINE__, __FILE__);
											 break;
										}
									DBG(fprintf(stderr, "element %s\n", n.name));
									break;
								case XML_TEXT_NODE:
									if (-1 == xmlTextWriterWriteString(writer,
																										 n.value)) 
										{
											 userReaderCtxtError(ctxt, SCDBXML_XML, __LINE__, __FILE__);
											 break;
										}
									DBG(fprintf(stderr, "text %s\n", n.value));
									break;
								case XML_COMMENT_NODE:
									if (-1 == xmlTextWriterWriteComment(writer,
																											n.value)) 
										{
											 userReaderCtxtError(ctxt, SCDBXML_XML, __LINE__, __FILE__);
											 break;
										}
									break;
									DBG(fprintf(stderr, "comment %s\n", n.value));
								case XML_PI_NODE:
									if (-1 == xmlTextWriterWritePI(writer,
																								 n.name,
																								 n.value)) 
										{
											 userReaderCtxtError(ctxt, SCDBXML_XML, __LINE__, __FILE__);
											 break;
										}
									DBG(fprintf(stderr, "PI %s\n", n.name));
									break;
								default:
									break;
							 } /* switch(n.type) */ 
						 
						 if (SCDBXML_OK != ctxt->error) 
							 {
									break;
							 }
				
						 /*
							* remember x and y if current node is element
							*/
						 if (n.type == XML_ELEMENT_NODE) 
							 {
									old_x = n.x;
									old_y = n.y;
									old_depth = n.depth;
							 }
					} /* for (i = 0; i < ctxt->node_count; ++ i) */
				
				if (SCDBXML_OK != ctxt->error) 
					{
						 break;
					}
	 
				/*
				 * now finish document, closing nodes
				 */
				if (-1 == xmlTextWriterEndDocument(writer)) 
					{
						 userReaderCtxtError(ctxt, SCDBXML_XML, __LINE__, __FILE__);
						 break;
					}
				
				/*
				 * free writer and return document
				 */
				xmlFreeTextWriter(writer);
				if (-1 == xmlDocDump(stdout, ctxt->doc)) 
					{
						 userReaderCtxtError(ctxt, SCDBXML_XML, __LINE__, __FILE__);
						 break;
					}
				
				break;
		 }
}
/*}}}*/
/************ buildDocument */
